import java.util.Arrays;

public class Array {
    public static void test() {
    }

    public static void test1() {
        int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组
        double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组
        String[] array3 = new String[3]; // 创建一个可以容纳3个字符串元素的数组

        //动态初始化：在创建数组时，直接指定数组中元素的个数
        //动态初始化,并不代表数组可以动态的变化的,也就是说不是动态数组,他的大小是固定的
        int[] array4 = new int[10];
        //静态初始化：在创建数组时不直接指定数据元素个数，而直接将具体的数据内容进行指定
        int[] array5 = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        double[] array6 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
        String[] array7 = new String[]{"hell", "Java", "!!!"};

        //【注意事项】
        //静态初始化虽然没有指定数组的长度，编译器在编译时会根据{}中元素个数来确定数组的长度
        //静态初始化时, {}中数据类型必须与[]前数据类型一致
        //静态初始化可以简写，省去后面的new T[]
        // 注意：虽然省去了new T[], 但是编译器编译代码时还是会还原
        int[] array8 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        double[] array9 = {1.0, 2.0, 3.0, 4.0, 5.0};
        String[] array10 = {"hell", "Java", "!!!"};

        //如果没有对数组进行初始化，数组中元素有其默认值
        //如果数组中存储元素类型为基类类型，默认值为基类类型对应的默认值
        //如果数组中存储元素类型为引用类型，默认值为null
        int[] array12 = new int[10];

        //数组在内存中是一段连续的空间，空间的编号都是从0开始的，依次递增，该编号称为数组的下标，数组可以通过下标访问其任意位置的元素
        int[] array11 = new int[]{10, 20, 30, 40, 50};
        System.out.println(array11[0]);
        System.out.println(array11[1]);
        System.out.println(array11[2]);
        System.out.println(array11[3]);
        System.out.println(array11[4]);
// 也可以通过[]对数组中的元素进行修改
        array11[0] = 100;
        System.out.println(array11[0]);

        //【注意事项】
        //1. 数组是一段连续的内存空间，因此支持随机访问，即通过下标访问快速访问数组中任意位置的元素
        //2. 下标从0开始，介于[0, N）之间不包含N，N为元素个数，不能越界，否则会报出下标越界异常

        //在Java中，数组是引用类型。尽管声明和使用数组的语法看起来像是基本类型，但实际上数组是对象
        // 例如，int[]是Object的一个子类。因此，数组有一些内置的特性和方法，其中之一就是length
        int[] array13 = new int[]{10, 20, 30, 40, 50};
        for (int i = 0; i < array13.length; i++) {
            System.out.println(array13[i]);
        }

        for (int e : array13) {
            System.out.println(e);
        }
    }

    //基本数据类型创建的变量，称为基本变量，该变量空间中直接存放的是其所对应的值；
    //而引用数据类型创建的变量，一般称为对象的引用，其空间中存储的是对象所在空间的地址
    public static void test2() {
        //在上述代码中，a、b、arr，都是函数内部的变量，因此其空间都在test2方法对应的栈帧中分配
        //a、b是内置类型的变量，因此其空间中保存的就是给该变量初始化的值
        //array是数组类型的引用变量，其内部保存的内容可以简单理解成是数组在堆空间中的首地址
        //引用变量并不直接存储对象本身，可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址，引用变量便可以去操作对象
        int a = 10;
        int b = 20;
        int[] arr = new int[]{1, 2, 3};

        int[] array1 = new int[3];
        array1[0] = 10;
        array1[1] = 20;
        array1[2] = 30;
        int[] array2 = new int[]{1, 2, 3, 4, 5};
        array2[0] = 100;
        array2[1] = 200;
        //array1去引用array2的空间,所以现在他们实际上是同一个数组
        array1 = array2;
        array1[2] = 300;
        array1[3] = 400;
        array2[4] = 500;
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }

        //null 在 Java 中表示 "空引用" , 也就是一个不指向对象的引用
        int[] array3 = null;
//        System.out.println(array3[0]);
        //null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置. 因此不能对这个内存进行任何读写操作
        // 一旦尝试读写, 就会抛出 NullPointerException
        //注意: Java 中并没有约定null和0号地址的内存有任何关联
    }

    //数组练习
    public static void test3() {
        //数组转字符串
        int[] array1 = new int[]{1, 2, 3, 4, 5, 6};
        //Java 中提供了 java.util.Arrays 包, 其中包含了一些操作数组的常用方法
        String strArray = Arrays.toString(array1);
        System.out.println(strArray);

        //数组拷贝
        // newArr1和array2引用的是同一个数组
        // 因此newArr1修改空间中内容之后，array2也可以看到修改的结果
        int[] array2 = {1, 2, 3, 4, 5, 6};
        int[] newArr1 = array2;
        newArr1[0] = 10;
        System.out.println("newArr: " + Arrays.toString(newArr1));

        // 使用Arrays中copyOf方法完成数组的拷贝：
        // copyOf方法在进行数组拷贝时，创建了一个新的数组
        // array2和newArr1引用的不是同一个数组
        array2[0] = 1;
        newArr1 = Arrays.copyOf(array2, array2.length);
        System.out.println("newArr: " + Arrays.toString(newArr1));

        // 因为array2修改其引用数组中内容时，对newArr1没有任何影响
        array2[0] = 10;
        System.out.println("arr: " + Arrays.toString(array2));
        System.out.println("newArr: " + Arrays.toString(newArr1));

        //拷贝某个范围
        //这个范围记得是左闭右开
        int[] array3 = Arrays.copyOfRange(array2, 1, 3);
        System.out.println("newArr3: " + Arrays.toString(array3));

        //数组排序
        int[] array4 = new int[]{9, 5, 2, 7};
        Arrays.sort(array4);
        System.out.println(Arrays.toString(array4));

        //二维数组
        //二维数组的用法和一维数组并没有明显差别
        //同理, 还存在 "三维数组", "四维数组" 等更复杂的数组, 只不过出现频率都很低
        int[][] arr = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };
        for (int row = 0; row < arr.length; row++) {
            for (int col = 0; col < arr[row].length; col++) {
                System.out.printf("%d\t", arr[row][col]);
            }
            System.out.println("");
        }
    }


    public static void main(String[] args) {
//        test1();
//        test2();
        test3();
    }
}
